#============================================================
#	Node Util
#============================================================
# @datetime: 2022-7-31 18:31:44
#============================================================
class_name NodeUtil


##  扫描所有子节点
##[br]
##[br][code]parent_node[/code]  开始的父节点
##[br][code]filter[/code]  过滤方法。这个方法有一个参数用于接收传入的节点，如果返回 true，则添加，否则不添加
##[br][code]return[/code]  返回扫描到的所有节点
static func get_all_child( parent_node: Node, filter := Callable() ) -> Array:
	var list = []
	var _scan_all_node = func(self_callable: Callable, _parent: Node):
		if filter.is_null():
			for child in _parent.get_children():
				list.append(child)
		else:
			for child in _parent.get_children():
				if filter.call(child):
					list.append(child)
		for child in _parent.get_children():
			self_callable.call(self_callable, child)
	_scan_all_node.call(_scan_all_node, parent_node)
	return list


##  创建一个计时器
##[br]
##[br][code]time[/code]  倒计时时间
##[br][code]to[/code]  添加到的节点
##[br][code]callable[/code]  回调方法
##[br][code]return[/code]  返回创建的 [Timer] 计时器
static func create_timer(time: float, to: Node, callable: Callable = Callable()) -> Timer:
	var timer := Timer.new()
	timer.wait_time = time
	if to.is_inside_tree():
		to.add_child(timer)
	else:
		to.add_child.call_deferred(timer)
	if not callable.is_null():
		timer.timeout.connect(callable)
	return timer


##  创建一个一次性计时器
##[br]
##[br][code]time[/code]  时间
##[br][code]callable[/code]  回调方法
##[br][code]to[/code]  添加到这个节点上，如果为 null，则
##[br]
##[br][code]return[/code]  返回创建的 [Timer]
static func create_once_timer(time:float=1.0, callable:Callable=Callable(), to: Node = null) -> Timer:
	var timer := create_timer(time, Engine.get_main_loop().current_scene if to==null else to, callable)
	timer.one_shot = true
	timer.timeout.connect(timer.queue_free)
	if timer.is_inside_tree():
		timer.start(time)
	else:
		timer.autostart = true
	return timer


##  根据 [AnimatedSprite2D] 当前的 frame 创建一个 [Sprite2D]
##[br]
##[br][code]animation_sprite[/code]  [AnimatedSprite2D] 类型的节点
##[br][code]return[/code]  返回一个 [Sprite2D] 节点
static func create_sprite_by_animated_sprite_current_frame(animation_sprite: AnimatedSprite2D) -> Sprite2D:
	var anim = animation_sprite.animation
	var idx = animation_sprite.frame
	var texture = animation_sprite.frames.get_frame(anim, idx)
	var sprite = Sprite2D.new()
	sprite.texture = texture
	sprite.global_position = animation_sprite.global_position
	sprite.offset = animation_sprite.offset
	return sprite


##  获取场景树
##[br]
##[br][code]return[/code]  返回场景树
static func get_tree() -> SceneTree:
	return Engine.get_main_loop().root.get_tree()


##  获取当前场景
##[br]
##[br][code]return[/code]  返回当前场景节点
static func get_current_scene() -> Node:
	return Engine.get_main_loop().current_scene


##  获取当前 2D 相机
##[br]
##[br][code]return[/code]  
static func get_current_camera2d() -> Camera2D:
	return get_current_scene().get_viewport().get_camera_2d()


##  根据 Class 获取父节点
##[br]
##[br][code]node[/code]  开始节点
##[br][code]_class[/code]  祖父节点的类
##[br][code]return[/code]  返回符合的类的祖父节点
static func get_parent_by_class(node: Node, _class) -> Node:
	var p = node.get_parent()
	while not p is _class and p != node.get_tree().root:
		p = p.get_parent()
	return p


##  获取 [AnimatedSprite2D] 的动画的播放时长
static func get_animation_sprite_time(animated_sprite: AnimatedSprite2D, animations) -> float:
	if animations is String or animations is StringName:
		if animated_sprite:
			var count = animated_sprite.frames.get_frame_count(animations)
			var speed = 1.0 / animated_sprite.frames.get_animation_speed(animations)
			return speed * count / animated_sprite.speed_scale
	elif animations is Array:
		var time = 0.0
		for animation in animations:
			time += get_animation_sprite_time(animated_sprite, animation)
		return time
	else:
		assert(false, "不能是 String 和 Array 之外的类型")
	return 0.0


## 添加节点到当前场景
##[br]
##[br][code]node[/code]  要添加的节点
##[br][code]callable[/code]  节点 ready 后调用的方法
##[br][code]signal_name[/code]  要连接到的信号名
static func add_node_to_current_scene(
	node: Node, 
	callable: Callable= Callable(), 
	signal_name: StringName = &"ready"
) -> void:
	(Engine.get_main_loop().current_scene as Node).add_child.call_deferred(node)
	if not callable.is_null():
		node.connect(signal_name, callable, Object.CONNECT_ONE_SHOT)


##  添加节点列表到节点中
##[br]
##[br][code]to[/code]  要添加到的节点
##[br][code]node_list_or_callable[/code]  节点列表，或者返回节点列表的 [Callable] 对象
##[br][code]force_readable_name[/code]  强制设置可读性强的名称
##[br][code]internal[/code]  是否为内部的节点，详见：[member Node.INTERNAL_MODE_BACK]
static func add_to_node_list(
	to: Node, 
	node_list_or_callable, 
	force_readable_name: bool = false, 
	internal: int = 0
):
	var node_list : Array
	if node_list_or_callable is Callable:
		node_list = node_list_or_callable.call()
	elif node_list_or_callable is Array:
		node_list = node_list_or_callable
	else:
		assert(false, "错误的参数类型：node_list_or_callable > " + node_list_or_callable)
	for node in node_list:
		to.add_child(node, force_readable_name, internal)


## 实例化这个类型下的场景
##[br]
##[br][code]class_[/code]  类型
static func instance_class_scene(class_: Script):
	var path := class_.resource_path
	var ext := path.get_extension()
	var file = path.substr(0, len(path) - len(ext))
	
	var scene: PackedScene
	if FileAccess.file_exists(file + "tscn"):
		scene = load(file + "tscn") as PackedScene
	elif FileAccess.file_exists(file + "scn"):
		scene = load(file + "scn") as PackedScene
	else:
		printerr("这个类目录下没有相同名称的场景文件！")
		return null
	
	return scene.instantiate()


##  延迟移除
##[br]
##[br][code]node[/code]  移除节点
##[br][code]time[/code]  延迟时间
static func delay_free(node: Node, time: float):
	get_tree().create_timer(time).timeout.connect(node.queue_free)

